package com.childenglish.controller;

import com.childenglish.entity.SysUser;
import com.childenglish.entity.SysRolePermission;
import com.childenglish.entity.SysClass;
import com.childenglish.entity.SysStudentClass;
import com.childenglish.mapper.SysUserMapper;
import com.childenglish.mapper.SysRolePermissionMapper;
import com.childenglish.mapper.SysClassMapper;
import com.childenglish.mapper.SysStudentClassMapper;
import com.childenglish.controller.CaptchaController;
import com.childenglish.service.OnlineUserService;
import com.childenglish.utils.DataEncryptionUtils;
import com.childenglish.utils.JwtUtil;
import com.childenglish.utils.PasswordEncoderUtil;
import com.childenglish.utils.R;
import com.childenglish.utils.SecurityAuditLogger;
import java.util.Map;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
public class LoginController {
    
    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysRolePermissionMapper sysRolePermissionMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private CaptchaController captchaController;

    @Autowired
    private OnlineUserService onlineUserService;

    @Autowired
    private SysStudentClassMapper sysStudentClassMapper;

    @Autowired
    private SysClassMapper sysClassMapper;

    /**
     * 处理GET请求到/login端点（用于直接访问时提供提示）
     */
    @GetMapping("/login")
    public R loginGet() {
        return R.error("请使用POST方法提交登录请求。此端点仅支持POST方法。");
    }

    /**
     * 获取CSRF Token（备选端点，如果/api/csrf-token不可用）
     * CSRFFilter会自动将X-CSRF-TOKEN添加到响应头中
     */
    @GetMapping("/csrf-token")
    public R getCsrfToken() {
        Map<String, Object> data = new HashMap<>();
        data.put("message", "CSRF token已添加到响应头 X-CSRF-TOKEN 中");
        data.put("code", 200);
        return R.ok("CSRF Token获取成功").data(data);
    }

    @PostMapping("/login")
    public R login(@Valid @RequestBody LoginRequest request, HttpServletRequest httpRequest, HttpSession session) {
        String ipAddress = SecurityAuditLogger.getClientIp(httpRequest);
        String userAgent = SecurityAuditLogger.getUserAgent(httpRequest);
        
        try {
            logger.debug("登录请求: {}", request.getUsername());
            
            // 验证验证码（业务逻辑校验，保留）
            if (!captchaController.verifyCaptchaFromSession(session, request.getCaptcha())) {
                SecurityAuditLogger.logLogin(request.getUsername(), false, ipAddress, userAgent);
                return R.error("验证码错误或已过期");
            }

            // 从数据库查找用户（包含角色信息）
            SysUser user = sysUserMapper.findByUsername(request.getUsername());

            if (user == null) {
                logger.debug("登录失败: 用户不存在 - {}", request.getUsername());
                // 记录登录失败日志
                SecurityAuditLogger.logLogin(request.getUsername(), false, ipAddress, userAgent);
                return R.error("用户名或密码错误");
            }

            // 解密前端加密的密码
            String rawPassword = com.childenglish.utils.UserDataHelper.decryptPassword(request.getPassword());

            // 使用BCrypt验证密码
            boolean passwordMatches;
            if (PasswordEncoderUtil.isBCryptFormat(user.getPassword())) {
                // BCrypt格式密码
                passwordMatches = PasswordEncoderUtil.matches(rawPassword, user.getPassword());
            } else {
                // 兼容旧密码（迁移期间）
                passwordMatches = user.getPassword().equals(rawPassword);
                // 如果是旧密码且验证成功，自动升级为BCrypt
                if (passwordMatches) {
                    String encodedPassword = PasswordEncoderUtil.encode(rawPassword);
                    user.setPassword(encodedPassword);
                    sysUserMapper.updatePassword(user.getId(), encodedPassword);
                    logger.info("密码已自动升级为BCrypt格式: {}", user.getUsername());
                }
            }

            if (passwordMatches) {
                // 生成JWT Token
                String token = jwtUtil.generateToken(user.getId(), user.getUsername(), user.getRole());
                
                // 记录用户在线状态（支持多人同时登录）
                String sessionId = session.getId();
                onlineUserService.recordUserLogin(user.getId(), user.getUsername(), 
                    user.getRole(), sessionId, ipAddress, userAgent);
                
                // 登录成功，返回用户信息和token（邮箱和手机号脱敏处理）
                Map<String, Object> userInfo = convertUserToSafeMap(user);
                Map<String, Object> data = new HashMap<>();
                data.put("user", userInfo);
                data.put("token", token);
                
                // 添加用户会话数量信息
                int sessionCount = onlineUserService.getUserSessionCount(user.getId());
                data.put("sessionCount", sessionCount);

                logger.info("登录成功: {} - 角色: {} - 当前会话数: {}", 
                    user.getUsername(), user.getRole(), sessionCount);
                
                // 记录登录成功日志
                SecurityAuditLogger.logLogin(user.getUsername(), true, ipAddress, userAgent);
                
                return R.ok("登录成功").data(data);
            } else {
                logger.debug("登录失败: 用户名或密码错误 - {}", request.getUsername());
                // 记录登录失败日志
                SecurityAuditLogger.logLogin(request.getUsername(), false, ipAddress, userAgent);
                return R.error("用户名或密码错误");
            }
        } catch (Exception e) {
            logger.error("登录异常: {}", e.getMessage(), e);
            // 记录登录异常日志
            SecurityAuditLogger.logLogin(request.getUsername(), false, ipAddress, userAgent);
            return R.error("登录失败: " + e.getMessage());
        }
    }

    @GetMapping("/user/info")
    public R getUserInfo() {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (subject.isAuthenticated()) {
                SysUser currentUser = (SysUser) subject.getPrincipal();
                // 对邮箱和手机号进行脱敏处理
                Map<String, Object> userInfo = convertUserToSafeMap(currentUser);
                Map<String, Object> data = new HashMap<>();
                data.put("user", userInfo);
                return R.ok().data(data);
            } else {
                return R.error("用户未登录");
            }
        } catch (Exception e) {
            System.err.println("获取用户信息失败: " + e.getMessage());
            return R.error("获取用户信息失败");
        }
    }

    /**
     * 将SysUser转换为安全的Map（邮箱和手机号脱敏处理）
     */
    private Map<String, Object> convertUserToSafeMap(SysUser user) {
        Map<String, Object> userMap = new HashMap<>();
        userMap.put("id", user.getId());
        userMap.put("username", user.getUsername());
        userMap.put("nickname", user.getNickname());
        userMap.put("role", user.getRole());
        userMap.put("userType", user.getUserType());
        userMap.put("createdTime", user.getCreatedTime());
        
        // 如果是学生（user_type='02'），添加班级信息
        if ("02".equals(user.getUserType())) {
            try {
                List<SysStudentClass> studentClasses = sysStudentClassMapper.findByStudentId(user.getId());
                if (studentClasses != null && !studentClasses.isEmpty()) {
                    SysStudentClass studentClass = studentClasses.get(0);
                    Long classId = studentClass.getClassId();
                    userMap.put("classId", classId);
                    
                    // 获取班级名称
                    SysClass classInfo = sysClassMapper.findById(classId);
                    if (classInfo != null) {
                        userMap.put("className", classInfo.getClassName());
                    } else {
                        userMap.put("className", "未知班级");
                    }
                } else {
                    userMap.put("classId", null);
                    userMap.put("className", "未分配班级");
                }
            } catch (Exception e) {
                System.err.println("获取学生班级信息失败: " + e.getMessage());
                userMap.put("classId", null);
                userMap.put("className", "未知班级");
            }
        }
        
        // 邮箱和手机号需要先解密再脱敏
        if (user.getEmail() != null && !user.getEmail().isEmpty()) {
            try {
                // 尝试解密（如果是加密的）
                String email = DataEncryptionUtils.decryptSensitiveField(user.getEmail());
                userMap.put("email", maskEmail(email));
            } catch (Exception e) {
                // 如果解密失败，可能是未加密的，直接脱敏
                userMap.put("email", maskEmail(user.getEmail()));
            }
        } else {
            userMap.put("email", null);
        }
        
        if (user.getPhone() != null && !user.getPhone().isEmpty()) {
            try {
                // 尝试解密（如果是加密的）
                String phone = DataEncryptionUtils.decryptSensitiveField(user.getPhone());
                userMap.put("phone", maskPhone(phone));
            } catch (Exception e) {
                // 如果解密失败，可能是未加密的，直接脱敏
                userMap.put("phone", maskPhone(user.getPhone()));
            }
        } else {
            userMap.put("phone", null);
        }
        
        // 不返回密码
        return userMap;
    }

    /**
     * 脱敏邮箱
     */
    private String maskEmail(String email) {
        if (email == null || email.isEmpty()) {
            return "";
        }
        int atIndex = email.indexOf("@");
        if (atIndex > 1) {
            return email.charAt(0) + "**" + email.substring(atIndex);
        }
        return "***" + (atIndex > 0 ? email.substring(atIndex) : "");
    }

    /**
     * 脱敏手机号
     */
    private String maskPhone(String phone) {
        if (phone == null || phone.isEmpty()) {
            return "";
        }
        if (phone.length() == 11) {
            return phone.substring(0, 3) + "****" + phone.substring(7);
        }
        return "****";
    }

    /**
     * 用户登出
     */
    @PostMapping("/logout")
    public R logout(HttpServletRequest httpRequest, HttpSession session) {
        try {
            String sessionId = session.getId();
            logger.info("收到登出请求，会话ID: {}", sessionId);
            
            // 在会话失效之前，先获取当前登录用户信息
            Long currentUserId = null;
            String currentUsername = null;
            
            // 方法1：尝试从Shiro Session获取
            try {
                Subject subject = SecurityUtils.getSubject();
                logger.debug("Shiro Subject状态: isAuthenticated={}", subject.isAuthenticated());
                if (subject.isAuthenticated()) {
                    Object principal = subject.getPrincipal();
                    logger.debug("Shiro Principal类型: {}", principal != null ? principal.getClass().getName() : "null");
                    if (principal instanceof SysUser) {
                        SysUser currentUser = (SysUser) principal;
                        currentUserId = currentUser.getId();
                        currentUsername = currentUser.getUsername();
                        logger.info("从Shiro Session获取当前登录用户ID: {} ({})", currentUserId, currentUsername);
                    } else {
                        logger.warn("Shiro Principal不是SysUser类型: {}", principal);
                    }
                } else {
                    logger.warn("Shiro Subject未认证");
                }
            } catch (Exception e) {
                logger.warn("从Shiro Session获取用户失败: {}", e.getMessage(), e);
            }
            
            // 方法2：如果Shiro Session获取失败，尝试从Redis查找当前sessionId对应的最新用户
            if (currentUserId == null) {
                try {
                    Map<String, Object> latestSession = onlineUserService.getLatestSessionBySessionId(sessionId);
                    if (latestSession != null) {
                        Object userIdObj = latestSession.get("userId");
                        if (userIdObj != null) {
                            currentUserId = ((Number) userIdObj).longValue();
                            currentUsername = (String) latestSession.get("username");
                            logger.info("从Redis查找当前sessionId对应的用户ID: {} ({})", currentUserId, currentUsername);
                        }
                    }
                } catch (Exception e) {
                    logger.warn("从Redis查找用户失败: {}", e.getMessage());
                }
            }
            
            // 记录用户登出（清理Redis中的会话数据和在线状态）
            // 如果知道当前用户ID，只清理该用户的会话；否则清理所有使用该sessionId的用户会话
            if (currentUserId != null) {
                logger.info("清理用户 {} ({}) 的会话: {}", currentUserId, currentUsername, sessionId);
                onlineUserService.recordUserLogout(currentUserId, sessionId);
            } else {
                logger.warn("无法确定当前用户ID，将清理所有使用该sessionId的用户会话: {}", sessionId);
                onlineUserService.recordUserLogout(sessionId);
            }
            
            // 使会话失效
            session.invalidate();
            
            logger.info("登出成功，已清理会话和在线状态，会话ID: {}", sessionId);
            return R.ok("登出成功");
        } catch (Exception e) {
            logger.error("登出失败: {}", e.getMessage(), e);
            return R.error("登出失败: " + e.getMessage());
        }
    }

    /**
     * 获取所有在线用户列表（管理员功能）
     */
    @GetMapping("/admin/online-users")
    public R getOnlineUsers() {
        try {
            List<Map<String, Object>> onlineUsers = onlineUserService.getAllOnlineUsers();
            Map<String, Object> data = new HashMap<>();
            data.put("onlineUsers", onlineUsers);
            data.put("totalCount", onlineUsers.size());
            return R.ok("获取在线用户列表成功").data(data);
        } catch (Exception e) {
            System.err.println("获取在线用户列表失败: " + e.getMessage());
            return R.error("获取在线用户列表失败: " + e.getMessage());
        }
    }

    /**
     * 获取在线用户总数
     */
    @GetMapping("/admin/online-users/count")
    public R getOnlineUserCount() {
        try {
            int count = onlineUserService.getOnlineUserCount();
            Map<String, Object> data = new HashMap<>();
            data.put("count", count);
            return R.ok("获取在线用户总数成功").data(data);
        } catch (Exception e) {
            System.err.println("获取在线用户总数失败: " + e.getMessage());
            return R.error("获取在线用户总数失败: " + e.getMessage());
        }
    }

    /**
     * 获取指定用户的所有会话信息
     */
    @GetMapping("/admin/user/{userId}/sessions")
    public R getUserSessions(@PathVariable Long userId) {
        try {
            List<Map<String, Object>> sessions = onlineUserService.getUserSessions(userId);
            Map<String, Object> data = new HashMap<>();
            data.put("userId", userId);
            data.put("sessions", sessions);
            data.put("sessionCount", sessions.size());
            return R.ok("获取用户会话信息成功").data(data);
        } catch (Exception e) {
            System.err.println("获取用户会话信息失败: " + e.getMessage());
            return R.error("获取用户会话信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取当前用户权限列表 - 修改为支持根据用户ID查询
     */
    @GetMapping("/user/permissions")
    public R getUserPermissions(@RequestParam(required = false) Long userId) {
        try {
            Long targetUserId = userId;

            // 如果没有提供userId，尝试从Shiro会话获取当前用户
            if (targetUserId == null) {
                Subject subject = SecurityUtils.getSubject();
                if (subject.isAuthenticated()) {
                    SysUser currentUser = (SysUser) subject.getPrincipal();
                    targetUserId = currentUser.getId();
                }
            }

            if (targetUserId == null) {
                return R.error("无法确定用户ID");
            }

            logger.debug("获取用户权限，用户ID: {}", targetUserId);

            // 从数据库查询用户权限
            List<SysRolePermission> permissions = sysRolePermissionMapper.findByUserId(targetUserId);
            List<String> permissionCodes = permissions.stream()
                    .map(SysRolePermission::getPermissionCode)
                    .filter(code -> code != null && !code.trim().isEmpty())
                    .collect(Collectors.toList());

            Map<String, Object> data = new HashMap<>();
            data.put("permissions", permissionCodes);
            data.put("userId", targetUserId);

            logger.debug("用户 {} 的权限: {}", targetUserId, permissionCodes);

            return R.ok("获取权限成功").data(data);

        } catch (Exception e) {
            logger.error("获取用户权限失败: {}", e.getMessage(), e);
            return R.error("获取权限失败: " + e.getMessage());
        }
    }

    // 登录请求对象
    public static class LoginRequest {
        @NotBlank(message = "用户名不能为空")
        private String username;

        @NotBlank(message = "密码不能为空")
        private String password;

        @NotBlank(message = "验证码不能为空")
        private String captcha;

        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public String getCaptcha() { return captcha; }
        public void setCaptcha(String captcha) { this.captcha = captcha; }
    }
}